<?php
/* class represents the blog itself */
class blog{	
	// private handle for the db
	public $db;
	public $cache;
	
	/* constructor loads the blog */
	function __construct($domain){
		// instanciate the database class
		$this->db = new database();
		
		// set the site id to use with this site
		$site_id = $this->db->getSiteIdByDomain($domain);

		if($site_id==-1){
			// redirect the client to the default site when
			// the domain is not configured in the system
			$default_domain = $this->db->getDefaultDomain();
			if(strlen($default_domain)>0){
				// redirect the user to the default domain
				header("HTTP/1.1 301 Moved Permanently"); 
				header("Location: http://".$default_domain."/"); 
				header("Connection: close"); 

				// the application needs to die here
				// which is ugly, but otherwise multiple
				// redirect headers will be sent
				die();
			}else{
				// die when this config failure occurs
				die("DOMAIN UNCONFIGURED AND "
					."NO DEFAULT DOMAIN EXISTS");
			}
		}else{			
			// set the site id in the database class for further use
			$this->db->setSite($this->db->getSiteIdByDomain($domain));

			// set the language for this site and just use
			// the first item in the language list as currently
			// our system does not support multi-language sites
			// and instead the recommend implementation is to have
			// a separate site for each language as the culture and
			// user behaviour also changes - nevertheless the db
			// is prepared to have that one day maybe.
			$langList = $this->db->getLanguageList();
			$this->db->setLanguageCode($langList[0]["code"]);
			
			// finally set the global configuration
			$this->setGlobalConfiguration();

			// instanciate the local cache
			$this->cache = new cache();
		}
	}

	/* returns the user object for the current user */
	public function getUser(){
		return new user($this->db);
	}

	/* returns the current email object for mailings */
	public function getEmail(){
		return new email($this->db);
	}
	
	/* this method retrieves all settings from the database 
	 * and updates the configuration for the site by setting 
	 * the global configuration setting using <define()> */
	private function setGlobalConfiguration(){
		// read all settings from the database
		$settings = $this->db->getSettingList();
		for($s=0;$s<count($settings);$s++){
			// TIMEZONE requires a different call than <define()>
			if($settings[$s]["code"]=="TIMEZONE"){
				if(strlen($settings[$s]["value"])>0){
					// update the timezone
					date_default_timezone_set($settings[$s]["value"]);
				}
			}
			// the locale requires a different call as well
			if($settings[$s]["code"]=="LC_TIME"){
				setlocale(LC_TIME, $settings[$s]["value"]);
			}
			// only set the global constant when its 
			// not yet defined elsewhere in the config.php f.e.
			$constantConfigName = "CONFIG_".$settings[$s]["code"];
			if(!defined($constantConfigName)){
				// use define to set the global config value
				define($constantConfigName,$settings[$s]["value"]);
			}
		}
	}

	/* this method returns the IP version that was used
		for the request of this page (IPv4 or IPv6) */
	public function getIPVersion(){
		$result = "IPv4";

		$ip = $_SERVER['REMOTE_ADDR'];

		if ($ip == "") {
        	$ip = ipv6::get_ip();
      	}

      	if (substr_count($ip,":") > 0 && substr_count($ip,".") == 0) {
        	$result = "IPv6";
      	}

      	return $result;
	}
	
	/* returns the latest articles where the param defines
	 * how many of the latest articles should be returned */
	public function getLatestArticles($articleCount){
		$result = array();
		$list = $this->db->getArticleList();
		$max = $articleCount;
		
		/* decrease the number when there are not
		 * sufficient articles in the result list */
		if(count($list)<$max){
			$max = count($list);
		}
		
		$r = 0;
		for($a=0;$a<$max;$a++){
			/* check if the articles is already published */
			if($list[$a]["published"]=="1" && $list[$a]["date_ts"] < time()){
				$result[$r] = $list[$a];
				$r++;
			}
		}
		return $result;
	}

	/* returns the category for the url */
	public function getCategory($url){
		/* get the content from the db */
		$result = $this->db->getCategory($url);

		/* format the category in the same way 
			the articles are being formatted */
		$result["formatted_body"] = $this->prepareArticleBody($result["body"]);

		return $result;
	}
	
	/* returns the article for the url */
	public function getArticle($article,$preview = false){
		$result = null;
		$list = $this->db->getArticleList();
		for($a=0;$a<count($list);$a++){
			if($list[$a]["url"]==$article && ($list[$a]["date_ts"] < time() || $preview==true)){
				if($list[$a]["published"]=="1" || $preview == true){
					// this is the requested article and
					// it already is active and published
					// or we are in preview mode
					$result = $this->db->getArticle($list[$a]['url']);

					// prepare the body for publishing
					$result["formatted_body"] = $this->prepareArticleBody($result["body"]);
				}
			}
		}
		return $result;
	}
	
	/* this method changes the body by adding image 
	 * host names on which the images are located */
	public function updateCdnHtml($body){
		$result = $body;
		$hostlist = explode(";", CONFIG_CDN_IMG_DOMAIN);

		// match all image host tags for the CDN
		preg_match_all("|<([^>]*)\[CDNIMAGEHOST\]([^>]*)>|U", $result, $found);

		// ensure tags were found and replace them
		if(count($found)>0){
			// define which host to use
			$hostNumber = 0;

			// iterate through all found tags
			for($i=0;$i<count($found[0]);$i++){
				// determine the acutal image file name
				// that we can check agains the cdn file 
				// list we store in the cache
				$imageFilename = $found[0][$i];
				$imageFilename = substr($imageFilename, strrpos($imageFilename, "[CDNIMAGEHOST]")+14);
				
				if(strpos($imageFilename, "\"")>0){
					$imageFilename = substr($imageFilename, 0, strpos($imageFilename, "\""));
				}

				if(strpos($imageFilename, "'")>0){
					$imageFilename = substr($imageFilename, 0, strpos($imageFilename, "'"));	
				}

				$imageFilename = str_replace("');", "", $imageFilename);
				$imageFilename = str_replace("\");", "", $imageFilename);
				$imageFilename = str_replace("/img/", "", $imageFilename);

				// set the local image domain
				$imageHost = $hostlist[$hostNumber];
				
				// increase the host number so the
				// next file to be served out of 
				// the local server is served from
				// the next domain
				$hostNumber++;

				// start from beginning 
				// when last host reached
				if($hostNumber==count($hostlist)){
					$hostNumber = 0;
				}

				// update the HTML-tag that contains the cdn host tag first
				$updatedTag = str_replace("[CDNIMAGEHOST]",$imageHost, $found[0][$i]);

				// replace the old HTML including the host tag with the new tag
				$result = str_replace($found[0][$i], $updatedTag, $result);
			}
		}
	
		return $result;	
	}

	/* this method updates the product listings within the site and 
		masks the links to amazon that are used within these listings.
		This is primarily to hide advertising content from the user,
		the robots, but also to speed up the site with server-side
		caching of the images and text contents. */
	public function updateProductListings($body){
		$result = $body;

		// instanciate the amazon client class
		$amzn = new amazon($this->db->getLanguageCode());

		// find all iframe matches 
		preg_match_all("|<productbox>([^>]*)</productbox>|U", $body, $found);
		for($f=0;$f<count($found[0]);$f++){
			$productTag = $found[0][$f];
			$asin = $found[1][$f];
			// query the item identified by the asin
			$itemList = $amzn->getItemByASINCached($asin);

			$boxHtml = "";
			if(!isset($itemList->Items->Request->Errors->Error)){
				$itemObj = array();
				// get the tiny image as object image
				$itemObj["asin"] = $itemList->Items->Item->ASIN;
				$itemObj["title"] = $itemList->Items->Item->ItemAttributes->Title;
				$itemObj["manufacturer"] = $itemList->Items->Item->ItemAttributes->Manufacturer;
				if(isset($itemList->Items->Item->Offers->Offer->OfferListing->Availability)){
					$itemObj["availability"] = $itemList->Items->Item->Offers->Offer->OfferListing->Availability;
				}else{
					$itemObj["availability"] = "";
				}
				
				if(isset($itemList->Items->Item->OfferSummary->LowestNewPrice->Amount)){
					$itemObj["price"] = floatval($itemList->Items->Item->OfferSummary->LowestNewPrice->Amount)/100;
				}else{
					$itemObj["price"] = 9999.99;
				}

				$itemObj["link"] = $itemList->Items->Item->DetailPageURL;
				$itemObj["image"] = $itemList->Items->Item->ImageSets->ImageSet[0]->TinyImage->URL;

				$itemTpl = new Smarty();
				$itemTpl->assign("item",$itemObj);
				$boxHtml = $itemTpl->fetch("themes/default/lang/"
					.$this->db->getLanguageCode()."/productofferbox.tpl");
			}

			// replace the original iframe with the box code
			$result = str_replace($productTag, $boxHtml, $result);
		}

		return $result;
	}
	
	/* determines the feature image for this article 
	 * and returns its path */
	public function getArticleImage($body){
		$result = "";
		
		/* remove all slashes that might exist */
		$aBody = stripslashes($body);
		
		/* regexp match all image tags in the body */
		preg_match_all("|<img ([^>]*)>|U", $aBody, $found);
						
		/* replace all image tags with the updated url that contains the 
		 * image name for the server-side image scaler */
		for($i=0; $i<count($found[0]);$i++){
			// only take the first image that appears
			if($i==0){
				$imgtag = $found[0][$i];
				$result = substr($imgtag, strpos($imgtag, "src=\"")+5);
				$result = substr($result, 0, strpos($result, "\""));
				$result = substr($result, strrpos($result, "/")+1);
			}
		}

		// return the image
		return $result;
	}
	
	/* replaces image tags and their url with the correct 
	 * name of the script that properly resizes them on 
	 * the server side. Also prepares existing code blocks
	 * to be rendered correctly with syntax highlighting */
	public function prepareArticleBody($articleBody){
		$result = $articleBody;

		/* regexp match all image tags in the body */
		preg_match_all("|<img ([^>]*)>|U", $result, $found);
						
		/* replace all image tags with the updated url that contains the 
		 * image name for the server-side image scaler */
		for($i=0; $i<count($found[0]);$i++){
			$imgtag = $found[0][$i];
			$filename = substr($imgtag, strpos($imgtag, "src=\"")+5);
			$filename = substr($filename, 0, strpos($filename, "\""));
			$filename = substr($filename, strrpos($filename, "/")+1);	
			$filetitle = substr($filename,0,strrpos($filename, "."));
			$fileext = substr($filename,strrpos($filename, "."));
			$new_filename = "img/".$filetitle."_250x200".$fileext;

			$alttext = "";
			if(strpos($imgtag, "alt=\"")>0){
				$alttext = substr($imgtag, strpos($imgtag, "alt=\"")+5);
				$alttext = substr($alttext, 0, strpos($alttext, "\""));
			}

			// default updated tag with image box
			$updated_tag = "<div class='imagebox'>"
						."<div class=\"imageboximage\">"
						."<a href='/img/".$filename."' class='imageboxlink' target='_blank'>"
						."<img src='http://[CDNIMAGEHOST]/"
						.$new_filename."' alt='".$alttext."' width='250' height='200' />"
						."</a>"
						."</div>"
						."<div class=\"imageboxtext\">".$alttext."</div>"
						."</div>";

			// create a full wide image instead when it has the class
			if(strpos($imgtag, "class=\"fullimage\"")!==false){
				$new_filename = "/img/".$filetitle."_500".$fileext;
				$updated_tag = "<a href='/img/".$filename."' target='_blank'>"
						."<img src='".$new_filename."' alt='".$alttext."' class='articlewideimage' />"
						."</a>";
			}

			$result = str_replace($imgtag, $updated_tag, $result);
		}

		/* regexp match all code tags in the body */
		preg_match_all("|<code lang=\"([^>]*)\">([^>]*)<\/code>|U", $result, $found);
		for($c=0;$c<count($found[0]);$c++){
			$codetag = $found[0][$c];
			$codelang = $found[1][$c];
			$codetext = base64_decode($found[2][$c]); 
			$new_codetag = "<textarea class=\"codetextarea codelang_"
						.$codelang."\">".$codetext."</textarea>";
			$result = str_replace($codetag, $new_codetag, $result);
		}

		/* regexp match all video tags in the body */
		preg_match_all("|<youtubevideo>([^>]*)<\/youtubevideo>|U", $result, $found);
		for($c=0;$c<count($found[0]);$c++){
			$videotag = $found[0][$c];
			$videoId = $found[1][$c];
			$new_videotag = "<iframe src=\"http://www.youtube.com/"
						."embed/".$videoId."?rel=0&showinfo=0&hd=1\" "
						."class=\"articlevideo\" frameborder=\"0\"></iframe>";
			$result = str_replace($videotag, $new_videotag, $result);
		}

		return $result;
	}
	
	/* returns all articles for the category */
	public function getCategoryArticles($category){
		$result = array();
		
		// load the article and their categories
		$ac_list = $this->db->getArticleCategoryList();
		
		// get all active articles for this category
		$r=0;
		for($ac=0;$ac<count($ac_list);$ac++){
			// check if its the category requested
			if($ac_list[$ac]["category_url"]==$category){
				// make sure the article is active
				if($ac_list[$ac]["article_published"]=="1"
					&& $ac_list[$ac]["article_date_ts"] < time()){
					// this is active, add it
					$result[$r] = array();
					$result[$r]["title"] = $ac_list[$ac]["article_title"];
					$result[$r]["date"] = $ac_list[$ac]["article_date"];
					$result[$r]["date_ts"] = $ac_list[$ac]["article_date_ts"];
					$result[$r]["url"] = $ac_list[$ac]["article_url"];
					$r++;
				}	
			}
		}
		
		return $result;
	}
}
?>
